#include "number.h"
#include <stdio.h>

int int_to_zigzag(int n)
{
    return (n << 1) ^ (n >> 31);
}

int zigzag_to_int(int n)
{
    return ((unsigned int)n >> 1) ^ -(n & 1);
}

int64_t int64_to_zigzag(int64_t n)
{
    return (n << 1) ^ (n >> 63);
}

int64_t zigzag_to_int64(int64_t n)
{
    return ((uint64_t)n >> 1) ^ -(n & 1);
}

int pbc_encode32(int number, uint8_t buffer[5])
{
    int i;
    for (i = 0; i < 5; ++i)
    {
        if ((number & (~0x7f)) == 0)
        {
            buffer[i] = (uint8_t)number;
            break;
        }
        else
        {
            buffer[i] = (uint8_t)((number & 0x7f) | 0x80);
            number = ((uint32_t)number) >> 7;
        }
    }

    return i + 1;
}

int pbc_encode64(int64_t number, uint8_t buffer[10]) 
{
    int i;
    for (i = 0; i < 10; ++i)
    {
        if ((number & (~0x7f)) == 0)
        {
            buffer[i] = (uint8_t)number;
            break;
        }
        else
        {
            buffer[i] = (uint8_t)((number & 0x7f) | 0x80);
            number = ((uint64_t)number) >> 7;
        }
    }

    return i + 1;
}

int pbc_decode32(uint8_t buffer[5], int *result)
{
    int i, offset = 0;

    for (i = 0; i < 5; ++i, offset += 7)
    {
        uint8_t n = buffer[i];
        *result |= ((uint32_t)(n & 0x7f) << offset);
        
        if ((n & 0x80) != 0x80)
            break;
    }

    return i + 1;
}

int pbc_decode64(uint8_t buffer[10], int64_t *result)
{
    int i, offset = 0;
    *result = 0;

    for (i = 0; i < 10; ++i, offset += 7)
    {
        uint8_t n = buffer[i];
        *result |= ((uint64_t)(n & 0x7f) << offset);
        
        if ((n & 0x80) != 0x80)
            break;
    }

    return i + 1;
}

int pbc_encodef(float v, uint8_t * buffer) 
{
    union {
        float v;
        uint32_t e;
    } u;
    u.v = v;
    buffer[0] = (uint8_t) (u.e & 0xff);
    buffer[1] = (uint8_t) (u.e >> 8 & 0xff);
    buffer[2] = (uint8_t) (u.e >> 16 & 0xff);
    buffer[3] = (uint8_t) (u.e >> 24 & 0xff);

    return 4;
}


uint32_t pbc_decodeu32(uint8_t *buffer)
{
    uint32_t v = buffer[0] | buffer[1]<<8 | buffer[2]<<16 | buffer[3]<<24;
    return v;
}
